<?php
	/**
	 *	KLF Framework
	 *
	 *	Written by Kristian Oye <kristianoye@gmail.com> on Oct 22, 2011
	 *	Copyright (C) 2010-2011
	 */
	namespace KLF\System
	{
		/**
		 *  Base event type for the KLF Framework
		 *
		 *  @package KLF\System
		 *  @access public
		 *  @author Kristian Oye <kristianoye@gmail.com>
		 *  @since 0.1
		 *  
		 *  @method KEvent NewInstance
		 *  
		 *  @property array Arguments The arguments passed when the event fired.
		 *  @property mixed EventHandled The data passed by the handler to the event.
		 *  @property KObject EventHandler The object that handled the events.
		 *  @property KObject Owner The object that fired the event.
		 */
		class KEvent extends KObject
		{
			/**
			 * The arguments passed when the event was fired.
			 * 
			 * @var \KLF\System\KEvent $_rpropArguments
			 */
			protected $_rpropArguments;
			
			/**
			 * The object responsible for handling the event.
			 * @var \KLF\System\KObject $_propEventHandler
			 */
			protected $_rpropEventHandler;
			
			/**
			 * The flag that indicates whether the event was handled externally or not.
			 * @var boolean $_propEventHandled
			 */
			protected $_rpropEventHandled;
			
			/**
			 * The list of callbacks that receive notification of the event.
			 * 
			 * @var array $_Listeners
			 */
			protected $_Listeners;
			
			/**
			 * The object that fired the event.
			 * 
			 * @var \KLF\System\KComponent $_propOwner
			 */
			protected $_rpropOwner;
			
			/**
			 * Constructs a new event instance.
			 */
			public function __construct($owner=NULL)
			{
				$this->_rpropOwner = $owner;
				$this->_rpropArguments = null;
				$this->_Listeners = array();
			}
			
			/**
			 * Returns true if the event was handled by another object or false if not.
			 * @return boolean
			 */
			public function EventHandled()
			{
				return $this->_EventHandled;
			}
			
			/**
			 * Adds a listener to this event.
			 * 
			 * @author Kristian Oye <kristianoye@gmail.com>
			 * @since 0.1
			 * @param mixed $listener The callback listening for the event.
			 * @return bool
			 */
			public function AddListener($listener)
			{
				array_push($this->_Listeners, $listener);
				return true;
			}
			
			/**
			 * Creates an argument object when an event fires.
			 * 
			 * @param array $args
			 * @return \KLF\System\KEventArgs
			 */
			protected function CreateArgs($args)
			{
				return new KEventArgs($args);
			}
				
			/**
			 * Returns the arguments passed when the event was fired.
			 * 
			 * @author Kristian Oye <kristianoye@gmail.com>
			 * @since 0.1
			 * @return array
			 */
			public function GetArguments()
			{
				return $this->_rpropArguments;
			}
			
			/**
			 * Returns the Nth argument from the argument collection.
			 * 
			 * @param int $key The index into the array.
			 */
			public function GetArgument($key)
			{
				return isset($this->_rpropArguments[$key]) ? $this->_rpropArguments[$key] : NULL;
			}
			
			/**
			 * Returns the object that fired the event.
			 * 
			 * @author Kristian Oye <kristianoye@gmail.com>
			 * @since 0.1
			 * @return object
			 */
			public function GetOwner()
			{
				return $this->_rpropOwner;
			}
			
			/**
			 * This method alters event behavior.  If the method is overridden
			 * and returns true then the notification to event handlers will
			 * stop when one of the listeners returns a boolean true.
			 * 
			 * @return boolean
			 */
			public function StopEventPropOnReturnTrue()
			{
				return false;
			}
			
			/**
			 * Fires the event
			 */
			private function __invoke()
			{
				$args = func_get_args();
				
				$this->_rpropOwner = array_shift($args);
				$this->_rpropArguments = $this->CreateArgs($args);
				$this->_rpropEventHandler = null;
				$this->_rpropEventHandled = false;
				
				foreach($this->_Listeners as $listener)
				{
					$result = call_user_func_array($listener, array($this->_rpropOwner, $this));

					if (!isset($result))
					{
						continue;
					}
					else if (isset($result) && $this->StopEventPropOnReturnTrue())
					{
						$this->_rpropEventHandler = $listener;
						$this->_rpropEventHandled = true;
						return $result;
					}
				}
				return null;
			}
		}
	}
